package com.zaicheng.cloud.netty.server;
/**
 @author zaicheng
 @version 1.0
 @date 2022-04-19
 @email zzc15847256473@163.com
 */

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zaicheng.cloud.netty.protocol.MessageContext;
import com.zaicheng.cloud.netty.protocol.Request;
import com.zaicheng.cloud.netty.protocol.Response;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Objects;
import java.util.Random;

@Slf4j
public class NettyServerHandler extends ChannelInboundHandlerAdapter {

    private ApplicationContext applicationContext;
    public NettyServerHandler(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("服务端与客户端可以通信了....");
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("获取客户端发送的消息"+msg);
        if (msg instanceof MessageContext){
            channelRead0(ctx, (MessageContext) msg);
        }
    }

    public void channelRead0(ChannelHandlerContext ctx, MessageContext request) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        // 解析参数
        Object requestData = request.getData();
        Request requestJson = JSON.parseObject(JSONObject.toJSONString(requestData), Request.class);
        Class<?>[] paramTypes = requestJson.getParameterTypes();
        Class<?> clazz = requestJson.getClazz();
        String methodName = requestJson.getMethodName();
        Object[] args = requestJson.getArgs();

        Class<?> returnType = null;
        Object invoke = null;
        if (Objects.nonNull(paramTypes) && Objects.isNull(args)){
            // 反射调用
            Method method = clazz.getMethod(methodName);
            returnType = method.getReturnType();
            invoke = method.invoke(applicationContext.getBean(clazz), args);
        }else {
            if (paramTypes.length == args.length) {
                for (int i = 0; i < args.length; i++) {
                    Object object = JSON.parseObject(JSONObject.toJSONString(args[i]), paramTypes[i]);
                    args[i] = object;
                }
            }
            // 反射调用
            Method method = clazz.getMethod(methodName, paramTypes);
            returnType = method.getReturnType();
            invoke = method.invoke(applicationContext.getBean(clazz), args);
        }
        // 封装结果
        MessageContext messageContext = new MessageContext(String.valueOf(new Random().nextInt(9999)),true,new Response(true,invoke,returnType));
        log.info("RPC 请求调用 clazz:{} methodName:{}, response:{}", clazz.getName(), methodName, JSON.toJSON(messageContext));
        // 回写数据
        ctx.channel().writeAndFlush(messageContext);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.channel().close();
    }
}
